package com.tang.lts.core.jvmmonitor;

import com.tang.lts.core.jvmmonitor.mbean.JVMGC;
import com.tang.lts.core.jvmmonitor.mbean.JVMInfo;
import com.tang.lts.core.jvmmonitor.mbean.JVMMemory;
import com.tang.lts.core.jvmmonitor.mbean.JVMThread;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

/**
 * @author Tang
 * @classname JVMMonitor
 * @description [  ]
 * @date 2022/5/10 14:07
 */
public class JVMMonitor {

    private static final AtomicBoolean start = new AtomicBoolean(false);

    private static MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();

    private static AtomicInteger refCount;

    private static Logger logger = Logger.getLogger("JVMMonitor");

    static {

        String className = JVMMonitor.class.getName() + "$JVMMonitorReferenceCount";
        try {
            Class<?> aClass = ClassLoader.getSystemClassLoader().loadClass(className);
            Field refCountField = aClass.getDeclaredField("REF_COUNT");
            refCountField.setAccessible(true);
            refCount = (AtomicInteger) refCountField.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static AtomicInteger getRefCount() {
        return refCount;
    }

    private final static Map<String, Object> MONITOR_MAP = new HashMap<>();

    public static void start() {
        getRefCount().incrementAndGet();
        if (start.compareAndSet(false, true)) {
            MONITOR_MAP.put(JVMConstants.JMX_JVM_INFO_NAME, JVMInfo.getInstance());
            MONITOR_MAP.put(JVMConstants.JMX_JVM_MEMORY_NAME, JVMMemory.getInstance());
            MONITOR_MAP.put(JVMConstants.JMX_JVM_GC_NAME, JVMGC.getInstance());
            MONITOR_MAP.put(JVMConstants.JMX_JVM_THREAD_NAME, JVMThread.getInstance());

            // 注册到 mBeanServer
            for (Map.Entry<String, Object> entry : MONITOR_MAP.entrySet()) {
                try {
                    mBeanServer.registerMBean(entry.getValue(), new ObjectName(entry.getKey()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            logger.info("Start JVMMonitor succeed !");
        }

    }

    public static Map<String, Object> getAttributes(String jmxName, List<String> attributes) {
        Map<String, Object> map = new HashMap<>(attributes.size());
        Object instance = MONITOR_MAP.get(jmxName);
        for (String item : attributes) {
            try {
                Object result = instance.getClass().getMethod("get" + item, null)
                        .invoke(instance, null);
                map.put(item, result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    private static class JVMMonitorReferenceCount {
        private static final AtomicInteger REF_COUNT = new AtomicInteger(0);
    }

}